package com.rtf.framework.common.id.snowflake;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 不同部分的id生成类
 * @Author : liupeng
 * @Date : 2019-01-05
 * @Modified By
 */
@Slf4j
public class AppIDPartDefault implements AppIDPart {

    protected Integer[] machineIp = new Integer[]{} ;

    @Setter
    @Getter
    private Map<AppIDItem,Integer> idItems ;

    @Getter
    private static final LoadingCache<Long,ConcurrentHashMap<Long,Integer>> numCache = CacheBuilder.newBuilder()
            .expireAfterWrite(5 , TimeUnit.SECONDS)
            .softValues()
            .build(new CacheLoader<Long, ConcurrentHashMap<Long, Integer>>() {
                @Override
                public ConcurrentHashMap<Long, Integer> load(Long key) throws Exception {
                    return new ConcurrentHashMap();
                }
            }) ;

    private final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();


    /**
     * 设置当前的id组成信息
     * @param idItems
     */
    @Override
    public void setIdItems(Map<AppIDItem,Integer> idItems){
        this.idItems = idItems ;
    }

    /**
     * 获取二进制长度标示的最大十进制数
     * @param binaryLength
     * @return
     */
    public static int getMaxNum( int binaryLength ){
        return ( 1 << binaryLength ) - 1 ;
    }

    public static void main(String[] args) {
        System.out.println(getMaxNum(14));
    }

    /**
     * 获取本机器的ip地址
     * @return
     */
    public void initMachineIp(){
        if( machineIp.length < 4 ){
//            InetUtils inetUtils = null ;
//            try{
//                inetUtils = UtilBeanFactory.getApplicationContext().getBean( InetUtils.class ) ;
//
//                InetUtils.HostInfo hostInfo = inetUtils.findFirstNonLoopbackHostInfo() ;
//
//                machineIp = UtilIp.getIp4Parts( hostInfo.getIpAddress() ) ;
//
//                log.info( "使用本机ip地址: {}" , Joiner.on(".").join( machineIp )); ;
//            }catch( Exception e ){
                Random random = new Random( System.currentTimeMillis() ) ;
                Integer[] randomNums = new Integer[4] ;
                for( int i = 0 ; i<4;i++ ){
                    randomNums[ i ] = random.nextInt(250) ;
                }
                machineIp = randomNums ;
//                log.info( "使用随机ip地址: {}" , Joiner.on(".").join( machineIp )) ;
//            }

        }
    }

    @Override
    public String getName() {
        return "基于snowflake的id生成器";
    }

    /**
     * 按照秒生成唯一的随机数。
     * @param binaryLength
     * @return
     */
    @Override
    public Map<String,Long> getNumIndex(int binaryLength , long timeSeconds , Object object ){
        Map<String, Long> returnMap = Maps.newHashMapWithExpectedSize(2);
        initMachineIp() ;
        long random = 0 ;
        synchronized ( AppIDPartDefault.class ){
            // 生成一个随机的id
            ConcurrentHashMap<Long, Integer> numSets = numCache.getUnchecked( timeSeconds ) ;

            // 允许生成最大十进制数字
            int maxNum = getMaxNum(binaryLength) ;
            long now = 0;
            // 使用随机算法生成一个不重复的数字，避免固定的数值取余数运算时分布不均匀

            do {
                random = threadLocalRandom.nextInt( maxNum ) ;
                //如果当前时间大于时间搓，则用当前时间的组合，目的是为了减少当前组合的值碰撞造成死循环
                now = System.currentTimeMillis() / 1000;
                if (now > timeSeconds) {
                    numSets = numCache.getUnchecked(now);
                    timeSeconds = now;
                }
            }while ( numSets.containsKey( random ) ) ;
            //加入组合
            numSets.put( random, 0 ) ;
        }
        returnMap.put("random", random);
        returnMap.put("timeSeconds", timeSeconds);
        return returnMap ;
    }

    /**
     * 获取自定义字段内容索引
     * @param binaryLength
     * @return
     */
    @Override
    public long getCustomIndex(int binaryLength , long timeSeconds , Object object ){
        return 0 ;
    }

    /**
     * 获取机器的标识，默认收集第三部分，<b>在docker中宿主机的ip默认是第三部分</b>
     * @return
     */
    @Override
    public long getMachineIndex(int binaryLength , long timeSeconds , Object object ){
        initMachineIp() ;
        return machineIp.length < 4 ? 0 : machineIp[ machineIp.length - 1 ] ;
    }

    /**
     * 获取时间索引
     * @return
     */
    @Override
    public long getTimeIndex(Integer binaryLength , long timeSeconds , Object object ){
        return timeSeconds ;
    }

//    public static void main(String[] args) throws Exception {
//
//        Random random = new Random( System.currentTimeMillis() ) ;
//        Integer[] randomNums = new Integer[4] ;
//        for( int i = 0 ; i<4;i++ ){
//            randomNums[ i ] = random.nextInt(250) ;
//        }
//
//        System.out.println(Joiner.on(",").join( randomNums ));
//
//        for( int i = 0 ; i<4;i++ ){
//            randomNums[ i ] = random.nextInt(250) ;
//        }
//
//        System.out.println(Joiner.on(",").join( randomNums ));
//        AppIDPartDefault appIDPartDefault = new AppIDPartDefault() ;
//        appIDPartDefault.getMachineIndex( 8 , 1L , null ) ;

//        AppIDGenerator snowflake2IDGenerator = new AppIDGenerator() ;
//        long second = 0 ;
//        Long nextId = null ;
//        Stopwatch stopwatch = Stopwatch.createStarted() ;
//        while (stopwatch.elapsed(TimeUnit.SECONDS)<10){
//            second = (System.currentTimeMillis()/1000) ;
//            nextId = snowflake2IDGenerator.getNextId(null) ;
////            System.out.println(second+"== "+nextId);
//        }
//        stopwatch.stop() ;
//
//        for (Map.Entry<Long,Set<Integer>> entry : ((DefaultSnowflakeIDPart) snowflake2IDGenerator.getSnowflakeIDPart()).getNumCache().asMap().entrySet()) {
//            System.out.println(entry.getKey()+"  "+entry.getValue().size());
//        }
//
//        System.out.println("完成");
//
//    }
//    public static void main(String[] args) {
//        String hostIp = "" ;
//        try {
//            hostIp = InetAddress.getLocalHost().getHostAddress() ;
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//        List<Integer> tmpIp = null ;
//        //分割ip地址
//        List<String> ipParts = Splitter.on('.').trimResults().splitToList( hostIp ) ;
//        if( ipParts!=null && ipParts.size()==4 ){
//            tmpIp = Lists.newArrayListWithCapacity( 4 ) ;
//            for (String ipPart : ipParts) {
//                tmpIp.add( Ints.tryParse( ipPart ) ) ;
//            }
//        }
//
//
//
//    }

}
